#pragma once
#include <filesystem>
#include <ranges>
#include <format>
#include <fstream>
#include <iostream>
#include <sstream>
#include <variant>
#include <functional>
#include <unordered_map>

#include "setting.hpp"
#include "message.hpp"
#include "utility.hpp"

namespace my_log
{
    /*****************
     * 样式设计
     * ti 打印线程id
     * pi 打印进程id
     * fi 打印文件
     * li 打印行号
     * co 打印列号
     * lv 打印等级
     * lg 打印日志器 
     * ms 打印正文
     * 支持chrono样式
     ****************/

    // 日志格式单例类
    class log_format_setting
    {
    private:
        log_format_setting();
    public:
        // 获取日志格式配置文件路径
        inline std::filesystem::path& getPatPath() noexcept
        {
            if (_pat_init_path == "")
            {
                _pat_init_path = std::filesystem::current_path();
                _pat_init_path.append("pattern.conf");
            }
            return _pat_init_path;
        }

        // 获取日志格式数量
        inline size_t size() const noexcept
        {
            return _pat_form.size();
        }

        // 获取单例指针
        static log_format_setting& getInstance() noexcept;

        // 插入日志格式
        void insert(const std::string& name, const std::string& format_str);

        // 移除日志格式
        void remove(const std::string& name);

        // 修改日志格式
        void modify(const std::string& name, const std::string& format_str);

        // 提交格式更改(存入配置文件)
        void flush();

        // 查找并提取日志格式
        const std::string& at(const std::string& name) const;
    private:
        // 从配置文件加载日志格式
        void load_init();

        // 校验日志格式
        void format_check(const std::string& name, const std::string& format_str);
    private:
        // 日志格式配置文件路径
        std::filesystem::path _pat_init_path;
        // 日志格式字典
        std::unordered_map<std::string, std::string> _pat_form;
    };
}

// 自定义formatter特化类
// 标准类组件必须暴露
template<>
class std::formatter<my_log::log_message>
{
public:
    // 标准库parse函数
    // 格式串校验+解析
    template<typename ParseContext>
    constexpr ParseContext::iterator parse(ParseContext& context)
    {
        auto it = context.begin();
        auto end = context.end();
        // 大括号检测
        if (it == end)
        {
            if (*it == '}')
            {
                _type_status = _format_type::EMPTY;
                return it;
            }
            else
            {
                throw std::format_error("Missing '}' in format string.");
            }
        }
        // 已解析格式串字符数
        size_t total_count = 0;
        // 已解析类型字符数
        // 时间类型: 2字符
        // 日志类型: 2字符
        size_t type_count = 0;
        // 是否符合可解析类型标准
        bool is_target = false;
        // 是否为可解析类型
        bool has_type = false;
        char ch = *it;
        while (it != end)
        {
            if ((ch - 'a' >= 0 && ch - 'z' <= 0) || (ch - 'A' >= 0 && ch - 'Z' <= 0))
            {
                if (type_count == 0)
                {
                    _type_status = _format_type::LOG_MSG;
                    has_type = true;
                }
                if (type_count == 2 && _type_status == _format_type::LOG_MSG)
                {
                    throw std::format_error("too many log message in signle \"{}\"");
                }
                if (total_count == 128)
                {
                    throw std::format_error("too much type identifier in single \"{}\"");
                }
                _str += ch;
                ++type_count;
                ++total_count;
                is_target = true;
            }
            else if (ch == '%' && (_type_status != _format_type::LOG_MSG &&
                (type_count == 0 || (type_count % 2 == 0 || _str[total_count - 1] == '%'))))
            {
                if (type_count == 0)
                {
                    _type_status = _format_type::CHRONO;
                    has_type = true;
                }
                if (total_count == 128)
                {
                    throw std::format_error("too much type identifier in single \"{}\"");
                }
                _str += ch;
                ++type_count;
                is_target = true;
            }
            else if (ch == '}')
            {
                return it;
            }
            else
            {
                _str += ch;
                ++total_count;
            }
            if (type_count > 0 && is_target == false)
            {
                throw std::format_error("error type identifier in format string.");
            }
            ch = *(++it);
            is_target = false;
        }
        if (!has_type)
        {
            throw std::format_error("no type infomation.");
        }
        return it;
    }

    // 标准库format函数
    // 格式化输入字符串
    template<typename FmtContext>
    FmtContext::iterator format(const my_log::log_message& log_msg, FmtContext& context) const
    {
        if (_type_status != _format_type::EMPTY)
        {
            std::string tem;
            if (_type_status == _format_type::CHRONO)
            {
                tem += "{0:";
                tem += _str;
                tem += '}';
                std::chrono::zoned_time local_time(std::chrono::current_zone(), log_msg._cur_time);
                std::vformat_to(context.out(), tem, std::make_format_args(local_time));
            }
            else if (_type_status == _format_type::LOG_MSG)
            {
                tem += "{0:";
                tem += _get_log_msg_type.at(_str);
                tem += '}';
                if (_str == "ti")
                {
                    std::vformat_to(context.out(), tem, std::make_format_args(log_msg._tid));
                }
                else if (_str == "pi")
                {
                    std::vformat_to(context.out(), tem, std::make_format_args(log_msg._pid));
                }
                else if (_str == "li")
                {
                    std::vformat_to(context.out(), tem, std::make_format_args(log_msg._line));
                }
                else if (_str == "co")
                {
                    std::vformat_to(context.out(), tem, std::make_format_args(log_msg._column));
                }
                else if (_str == "fi")
                {
                    std::ranges::copy(log_msg._file, context.out());
                }
                else if (_str == "lv")
                {
                    std::ranges::copy(my_log::log_level::get_value(log_msg._level), context.out());
                }
                else if (_str == "lg")
                {
                    std::ranges::copy(log_msg._logger, context.out());
                }
                else if (_str == "ms")
                {
                    std::ranges::copy(log_msg._payload, context.out());
                }
                else
                {
                    throw std::format_error("unregistered type");
                }
            }
        }
        return context.out();
    }
private:
    // 格式串类型
    enum class _format_type : size_t
    {
        EMPTY = 0,
        CHRONO,
        LOG_MSG
    };
private:
    // 格式串类型
    _format_type _type_status = _format_type::EMPTY;
    // 有效格式串
    std::string _str;
    // 日志格式转换表
    static const std::unordered_map<std::string_view, std::string_view> _get_log_msg_type;
};